#include<string>
#include<vector>
#include<array>
#include<unordered_map>
#include<algorithm>
#include<limits>
#include <stack>
#include<iostream>
#include<sstream>
#include<deque>
#define MOD 1000000007
#include <vector>

class UnionFind {
private:
    std::vector<int> parent;  // 存储每个元素的父节点
    std::vector<int> rank;    // 存储每个集合的秩（用于按秩合并）
    int count;                // 元素的总数量

public:
    std::vector<int> maxI;
    // 构造函数，初始化并查集
    UnionFind(int size) : count(size) {
        parent.resize(size);
        rank.resize(size, 0);
        maxI.resize(size,1);
        
        // 初始化每个元素的父节点为自身
        for (int i = 0; i < size; ++i) {
            parent[i] = i;
            maxI[i] = 1;
        }
    }
    
    // 查找元素的根节点，使用路径压缩优化
    int find(int x) {
        // 如果x不是根节点，递归查找其父节点的根节点，并将x直接连接到根节点（路径压缩）
        if (parent[x] != x) {
            parent[x] = find(parent[x]);
        }
        return parent[x];
    }
    
    // 合并两个元素所在的集合，使用按秩合并优化
    int unite(int x, int y,const std::vector<int>& vals) {
        // 查找两个元素的根节点
        int rootX = find(x);
        int rootY = find(y);

        int path =0;
        // 如果已经在同一个集合中，则不需要合并
        if (vals[rootX] > vals[rootY])
        {
            parent[rootY] = rootX;
        }
        else if (vals[rootX] < vals[rootY])
        {
            parent[rootX] = rootY;
        }else
        {
            path = maxI[rootX] * maxI[rootY];
            parent[rootY] = rootX;
            maxI[rootX] += maxI[rootY];
        }
  return path;
    }
    
    // 判断两个元素是否在同一个集合中
    bool isConnected(int x, int y) {
        return find(x) == find(y);
    }
    
    // 获取当前集合的数量
    int getCount() const {
        return count;
    }
};


class Solution {
public:
    int numberOfGoodPaths(std::vector<int>& vals,std:: vector<std::vector<int>>& edges) {
        int vn = vals.size();
        int ans = vn;
        UnionFind uf(vn);
        std::sort(edges.begin(), edges.end(), [&](const std::vector<int>& e1, const std::vector<int>& e2) {
        int max1 = std::max(vals[e1[0]], vals[e1[1]]);
        int max2 =std:: max(vals[e2[0]], vals[e2[1]]);
        return max1 < max2;
    });
       int n = edges.size();
        for (int i = 0; i < n; ++i)
        {
            ans+= uf.unite(edges[i][0], edges[i][1], vals);
        }
        return ans;
    }
};